﻿#if NETFX

using System.Threading.Tasks;
using System.Net.Sockets;
using System.IO;
using System.Net;
using System;
using System.Threading;




namespace XmlSockets.Internal.AbSystem
{
    internal sealed class InternalSocket : IInternalSocket
    {

        public IEndPoint LocalEndPoint
        {
            get
            {
                return new AbEndPoint((IPEndPoint)this._socket.LocalEndPoint);
            }
        }

        public IEndPoint RemorteEndPoint
        {
            get
            {
                return new AbEndPoint((IPEndPoint)this._socket.RemoteEndPoint);
            }
        }

        public  async Task SendAsync(IXmlSocketSendContent content)
        {
            try
            {
                await Task.Factory.FromAsync<int>(this._socket.BeginSend(content.Buffer, 0, content.Buffer.Length, SocketFlags.None, null, null), this._socket.EndSend, TaskCreationOptions.None)
                      .ConfigureAwait(false);
            }
            catch (SocketException e)
            {

                throw new IOException("メッセージ送信中にソケットエラーが発生しました", e);
            }
        }

        public  async Task<IXmlSocketReceiveContent> ReceiveAsync(int size)
        {
            try
            {
                byte[] buffer = new byte[size];


                int recvLen = await Task.Factory.FromAsync<int>(this._socket.BeginReceive(buffer, 0, size, SocketFlags.None, null, null), this._socket.EndReceive, TaskCreationOptions.None)
                                    .ConfigureAwait(false);
                return new XmlSocketReceiveContent(buffer, recvLen);
            }
            catch (SocketException e)
            {
                throw new IOException("メッセージ受信中にソケットエラーが発生しました", e);
            }
        }


        public Task ConnectAsync(string hostName, int port)
        {
            try
            {
                return Task.Factory.FromAsync(this._socket.BeginConnect(hostName, port, null, null), this._socket.EndConnect, TaskCreationOptions.None);

            }
            catch (SocketException e)
            {
                throw new IOException("接続中にソケットエラーが発生しました", e);
            }
        }

        public   void Dispose()
        {



            if (this._socket.Connected) this._socket.Shutdown(SocketShutdown.Both);
            
#if NET40
            TaskEx.Run(async()=>

#else
            Task.Run(async()=>
#endif
            
            {

                

#if NET40
                await TaskEx.Delay(TimeSpan.FromSeconds(5)).ConfigureAwait(false);
#else
                await Task.Delay(TimeSpan.FromSeconds(5)).ConfigureAwait(false);
#endif

                this._socket.Close();
            });
            


            
           





        }



        public static InternalSocket Create()
        {
            return new InternalSocket();
        }

        public static InternalSocket Create(Socket socket)
        {
            return new InternalSocket(socket);
        }

        private Socket _socket;



        private
#if NET40
        InternalSocket() : this(new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { }
#else
 InternalSocket()
            : this(new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp)) { }
#endif

        private InternalSocket(Socket socket)
        {
            _socket = socket;

           

        }





        
    }



}
#endif